//
// Created by benxb on 2021/11/16.
//

#ifndef BENXDB_MEM_DATA_TABLE_H
#define BENXDB_MEM_DATA_TABLE_H

#include <catelog/table.h>
#include <memory>
#include <utility>
#include <common/timer.h>
#include "storage/data_chunk.h"
#include "tuple.h"
#include "catelog/query.h"
#include "log_manager.h"
#include <catelog/point_cloud.h>
#include <catelog/point_type.h>

namespace benxdb {

class MemDataTable {
public:
    explicit MemDataTable(const std::shared_ptr<Table>& table);

    explicit MemDataTable(const std::shared_ptr<Table>& table, uint64_t lsn);

    ~MemDataTable();

    void Clear();

    bool AppendTuple(Tuple& tuple);

    bool AppendManyTuples(std::vector<Tuple>& data_vec);

    bool AppendManyTuples(std::vector<Tuple>& tuples, int begin, int end);

    template<class PointT>
    bool AppendPointCloud(PointCloud<PointT>& point_cloud, int begin_index, int end_index, bool log = false) {
        timer_.Start();
        if (GetFreeRecordSlot() < end_index-begin_index+1) {
            return false;
        }

        log_manager_->AppendManyLog(point_cloud, begin_index, end_index);
        AppendPointXXX(point_cloud, begin_index, end_index);
        record_count_ += end_index-begin_index+1;
        timer_.PauseAndPrint("MemTable Append records.");
        return true;
    }


    bool AppendPointData(const char* point_data, int size);

    /**
     * check if the table is full of records
     * @return true if full
     */
    bool IsFull() const;

    bool IsEmpty() const;

    int GetRecordCount() const;

    int GetFreeRecordSlot() const;

    bool HasFreeRecordSlot() const;

    void Query(QueryPhrase query, std::vector<Tuple>& res);

    std::shared_ptr<DataChunk> GetChunkByIndex(int index);

    int ColumnSize();

    void SetLSN(lsn_t lsn);

    lsn_t GetLSN() const { return lsn_; }

    void QueryPointCloud(PointCloudQuery& query, PointCloud<PointXYZ>& res);

private:
    std::shared_ptr<Table> table_;
    // column-oriented
    std::vector<std::shared_ptr<DataChunk>> chunk_vec_;
    int record_count_{};
    // log sequence number
    lsn_t lsn_{};
    // log manager
    std::shared_ptr<LogManager> log_manager_;

    bool AppendManyTuplesWithoutLog(std::vector<Tuple>& data_vec);

    void AppendTupleWithoutLog(Tuple& tuple);

    bool AppendPointXXX(PointCloud<PointSTXYZ> &point_cloud, int begin_index, int end_index);

    bool AppendPointXXX(PointCloud<PointSTXYZC> &point_cloud, int begin_index, int end_index);

    Timer timer_;

    bool AppendPointXXX(PointCloud <PointXYZI> &point_cloud, int begin_index, int end_index);
};

}


#endif //BENXDB_MEM_DATA_TABLE_H
